package com.wgo.bpot.server.web.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.log4j.Logger;

import com.wgo.bpot.server.persist.PersistService;
import com.wgo.bpot.wiring.WiringEngine;

/**
 * A servlet filter that provides a thread-bound session-per-request.
 * <p>
 * This filter should be used if your
 * <tt>hibernate.current_session_context_class</tt> configuration is set to
 * <tt>thread</tt> and you are not using JTA/CMT. You can use this filter for
 * a thread-bound <tt>Session</tt>, either with resource-local transactions
 * (direct JDBC) or user-managed JTA transactions. Set your
 * <tt>hibernate.transaction.factory_class</tt> accordingly.
 * <p>
 * Note that you should not use this interceptor out-of-the-box with enabled
 * optimistic concurrency control. Apply your own compensation logic for failed
 * conversations, this is totally dependent on your applications design.
 * 
 * @see org.hibernate.ce.auction.persistence.TransactionInterceptor
 * 
 */
public class ServiceFilter implements Filter {
	private static Logger log = Logger.getLogger(ServiceFilter.class);
 	private PersistService persistService;

	public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
		log.debug("Starting a database transaction");
		persistService.openSession();
		persistService.startTransaction();
		try {
			chain.doFilter(request, response);
			log.debug("Committing the database transaction");
			persistService.commitTransaction();
		} catch (RuntimeException e) {
			try {
				log.debug("Trying to rollback database transaction after exception");
				persistService.rollbackTransaction();
			} catch (Throwable rbEx) {
				log.error("Could not rollback transaction after exception!",rbEx);
			}
			throw new ServletException(e);
		} finally {
			persistService.closeSession();
		}
	}

	public void init(FilterConfig filterConfig) throws ServletException {
		log.debug("Initializing filter...");
		String wiringEngineClassName = filterConfig.getInitParameter("wiring-engine");
		Class wiringEngineClass;
		try {
			wiringEngineClass = Class.forName(wiringEngineClassName);
		} catch (ClassNotFoundException e) {
			throw new ServletException("Could not 'wiring-engine' class", e);
		}
		Object wiringEngineObject;
		try {
			wiringEngineObject = wiringEngineClass.newInstance();
		} catch (Exception e) {
			throw new ServletException("Could instantiate 'wiring-engine'", e);
		}
		if (wiringEngineObject instanceof WiringEngine) {
			persistService = ((WiringEngine)wiringEngineObject).getServiceAccessor().getPersistService();
		} else {
			throw new ServletException("wiring-engine was not instance of WiringEngine");
		}
	}

	protected void setPersistService(PersistService persistService) {
		this.persistService = persistService;
	}

	public void destroy() {
		persistService = null;
	}

}